package com.xaicode.auth.domain;

import cn.hutool.http.HttpStatus;
import com.fasterxml.jackson.annotation.JsonIgnore;

import java.util.Objects;

import static cn.hutool.http.HttpStatus.HTTP_OK;

/**
 * 返回值包装类
 * <p>
 * 支持 {@link IErrorCode} 扩展
 * <p>
 * <b>本类为支持 isX() 方法而不使用 lombok</b>
 * 
 * @date 2022/6/20
 */
public class Result<T> {

    private static final String MSG_OK = "操作成功";
    private static final String MSG_FAIL = "操作失败";

    /**
     * 网络请求响应码
     */
    private long code = HTTP_OK;

    /**
     * 后台操作响应信息
     */
    private String message = MSG_OK;

    /**
     * 自定义返回数据
     */
    private T data;


    /**
     * 请求链路追踪ID，需主动设置
     */
    private String traceId;


    public Result() {
    }

    public Result(T t) {
        this.data = t;
    }

    public Result(String message, T t) {
        this.message = message;
        this.data = t;
    }

    public Result(long code, String message, T t) {
        this.code = code;
        this.message = message;
        this.data = t;
    }

    public long getCode() {
        return code;
    }

    public void setCode(long code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public void setTraceId(String traceId) {
        this.traceId = traceId;
    }

    public String getTraceId() {
        return traceId;
    }

    // ----

    @JsonIgnore
    public static Result<?> choose(boolean ok) {
        if (ok) {
            return ok();
        } else {
            return fail();
        }
    }

    /**
     * @return <pre>{@code
     * code=200
     * message=ok
     * data=null
     * }</pre>
     */
    @JsonIgnore
    public static Result<?> ok() {
        return new Result<>();
    }

    /**
     * @param t   T
     * @param <T> T
     * @return <pre>{@code
     * code=200
     * message=ok
     * data=t
     * }</pre>
     */
    @JsonIgnore
    public static <T> Result<T> ok(T t) {
        return new Result<>(t);
    }

    /**
     * @param message .
     * @param t       T
     * @param <T>     T
     * @return <pre>{@code
     * code=200
     * message=message
     * data=t
     * }</pre>
     */
    @JsonIgnore
    public static <T> Result<T> ok(String message, T t) {
        return new Result<>(message, t);
    }

    /**
     * @param message .
     * @param <T>     T
     * @return <pre>{@code
     * code=200
     * message=message
     * data=t
     * }</pre>
     */
    @JsonIgnore
    public static <T> Result<T> okMsg(String message) {
        return ok(message, null);
    }

    /**
     * @return <pre>{@code
     * code=500
     * message=fail
     * data=null
     * }</pre>
     */
    @JsonIgnore
    public static <T> Result<T> fail() {
        return fail(MSG_FAIL, null);
    }

    /**
     * @param message .
     * @param <T>     T
     * @return <pre>{@code
     * code=500
     * message=xxx
     * data=null
     * }</pre>
     */
    @JsonIgnore
    public static <T> Result<T> fail(String message) {
        return fail(HttpStatus.HTTP_INTERNAL_ERROR, message, null);
    }

    /**
     * @param code    http code
     * @param message msg
     * @return <pre>{@code
     * code=code
     * message=message
     * data=null
     * }</pre>
     */
    @JsonIgnore
    public static <T> Result<T> fail(long code, String message) {
        return fail(code, message, null);
    }

    /**
     * @param t       T
     * @param <T>     T
     * @param message msg
     * @return <pre>{@code
     * code=500
     * message=message
     * data=t
     * }</pre>
     */
    @JsonIgnore
    public static <T> Result<T> fail(String message, T t) {
        return fail(HttpStatus.HTTP_INTERNAL_ERROR, message, t);
    }

    /**
     * @param code    http code
     * @param t       T
     * @param <T>     T
     * @param message msg
     * @return <pre>{@code
     * code=code
     * message=message
     * data=t
     * }</pre>
     */
    @JsonIgnore
    public static <T> Result<T> fail(long code, String message, T t) {
        Result<T> result = new Result<>();
        result.setCode(code);
        result.setMessage(message);
        result.setData(t);
        return result;
    }

    @JsonIgnore
    public static <T> Result<T> fail(IErrorCode code) {
        Result<T> result = new Result<>();
        result.setCode(code.getCode());
        result.setMessage(code.getMessage());
        return result;
    }

    @JsonIgnore
    public static <T> Result<T> fail(IErrorCode code, T t) {
        Result<T> result = new Result<>();
        result.setCode(code.getCode());
        result.setMessage(code.getMessage());
        result.setData(t);
        return result;
    }

    /**
     * 判断请求是否正确，当前仅判断状态为{@link HttpStatus#HTTP_OK}的请求为正确
     *
     * @return true 请求正确
     */
    @JsonIgnore
    public boolean isOk() {
        return this.code == HTTP_OK;
    }

    /**
     * 判断请求是否错误
     *
     * @return true 请求错误
     */
    @JsonIgnore
    public boolean isFail() {
        return !isOk();
    }

    /**
     * 判断请求是否错误或返回值是否为空
     *
     * @return true 请求异常
     */
    @JsonIgnore
    public boolean isFailOrDataNull() {
        return isFail() || Objects.isNull(this.data);
    }

    // ----

    public Result<T> code(long code) {
        this.code = code;
        return this;
    }

    public Result<T> code(IErrorCode r) {
        this.code = r.getCode();
        this.message = r.getMessage();
        return this;
    }

}
